from __future__ import annotations

import os
from pathlib import Path

import click
from dotenv import load_dotenv
from flask import Blueprint, Flask
from flask.cli import with_appcontext

BASE_DIR = Path(__file__).resolve().parent.parent

# /**
#  * 作者: "test_LH"
#  * 日期: 2025-10-11
#  * 名称: _load_environment
#  * 作用: 按优先级加载环境变量文件，确保应用配置可从 .env 文件读取
#  * 参数:
#  *   @param 无 函数不接受参数
#  * 返回: 无
#  * 备注: 无
#  */
def _load_environment() -> None:
    env_file = os.getenv("ENV_FILE")
    search_order = [env_file] if env_file else [".env", ".env.dev"]
    for candidate in search_order:
        if not candidate:
            continue
        candidate_path = BASE_DIR / candidate
        if candidate_path.exists():
            load_dotenv(candidate_path, override=False)
            break


_load_environment()

from .config import Config
from flask_security.utils import hash_password
from .extensions import api, db, jwt, migrate, security
from .models import Role, User
from .resources import auth_ns, demo_ns, user_ns


# /**
#  * 作者: "test_LH"
#  * 日期: 2025-10-11
#  * 名称: create_app
#  * 作用: 初始化 Flask 应用并注册扩展、蓝图及命令
#  * 参数:
#  *   @param config_class Flask 配置类，用于加载应用配置
#  * 返回: 已完成初始化的 Flask 应用实例
#  * 备注: 无
#  */
def create_app(config_class: type[Config] = Config) -> Flask:
    app = Flask(__name__)
    app.config.from_object(config_class)

    register_extensions(app)
    register_blueprints(app)
    register_shellcontext(app)
    register_commands(app)

    return app


# /**
#  * 作者: "test_LH"
#  * 日期: 2025-10-11
#  * 名称: register_extensions
#  * 作用: 将数据库、迁移、安全及 JWT 等扩展与应用绑定
#  * 参数:
#  *   @param app Flask 应用实例
#  * 返回: 无
#  * 备注: 无
#  */
def register_extensions(app: Flask) -> None:
    db.init_app(app)
    migrate.init_app(app, db)

    from flask_security import SQLAlchemyUserDatastore

    user_datastore = SQLAlchemyUserDatastore(db, User, Role)
    security.init_app(app, user_datastore)

    jwt.init_app(app)

    # /**
    #  * 作者: "test_LH"
    #  * 日期: 2025-10-11
    #  * 名称: _user_lookup_callback
    #  * 作用: 基于 JWT 内容加载当前请求关联的用户实体
    #  * 参数:
    #  *   @param _jwt_header JWT 请求头信息
    #  *   @param jwt_data 解码后的 JWT 数据载荷
    #  * 返回: 匹配到的用户对象或 None
    #  * 备注: 提供给 Flask-JWT-Extended 的用户加载回调
    #  */
    @jwt.user_lookup_loader
    def _user_lookup_callback(_jwt_header, jwt_data):
        identity = jwt_data["sub"]
        if identity is None:
            return None
        return User.query.filter_by(id=int(identity)).one_or_none()


# /**
#  * 作者: "test_LH"
#  * 日期: 2025-10-11
#  * 名称: register_blueprints
#  * 作用: 注册 API 蓝图及各个命名空间路由
#  * 参数:
#  *   @param app Flask 应用实例
#  * 返回: 无
#  * 备注: 无
#  */
def register_blueprints(app: Flask) -> None:
    api_bp = Blueprint("api", __name__, url_prefix="/api")
    api.init_app(api_bp)
    api.add_namespace(auth_ns, path="/auth")
    api.add_namespace(demo_ns, path="/demo")
    api.add_namespace(user_ns, path="/users")
    app.register_blueprint(api_bp)


# /**
#  * 作者: "test_LH"
#  * 日期: 2025-10-11
#  * 名称: register_shellcontext
#  * 作用: 在 Flask shell 中预加载常用对象便于调试
#  * 参数:
#  *   @param app Flask 应用实例
#  * 返回: 无
#  * 备注: 无
#  */
def register_shellcontext(app: Flask) -> None:
    # /**
    #  * 作者: "test_LH"
    #  * 日期: 2025-10-11
    #  * 名称: shell_context
    #  * 作用: 定义 Flask shell 可直接使用的对象映射
    #  * 参数:
    #  *   @param 无 函数不接受参数
    #  * 返回: 包含数据库对象及核心模型的字典
    #  * 备注: 无
    #  */
    @app.shell_context_processor
    def shell_context():
        return {"db": db, "User": User, "Role": Role}


# /**
#  * 作者: "test_LH"
#  * 日期: 2025-10-11
#  * 名称: register_commands
#  * 作用: 注册自定义 Flask CLI 命令供运维与初始化使用
#  * 参数:
#  *   @param app Flask 应用实例
#  * 返回: 无
#  * 备注: 无
#  */
def register_commands(app: Flask) -> None:
    # /**
    #  * 作者: "test_LH"
    #  * 日期: 2025-10-11
    #  * 名称: create_admin
    #  * 作用: 创建拥有 admin 和 user 角色的初始管理员账户
    #  * 参数:
    #  *   @param email 管理员登录使用的邮箱地址
    #  *   @param password 管理员初始密码
    #  * 返回: 无
    #  * 备注: 需要在应用上下文中执行
    #  */
    @app.cli.command("create-admin")
    @click.argument("email")
    @click.argument("password")
    @with_appcontext
    def create_admin(email: str, password: str) -> None:
        datastore = app.extensions["security"].datastore
        email_normalized = email.lower()
        if datastore.find_user(email=email_normalized):
            click.echo("用户已存在")
            return

        admin_role = datastore.find_role("admin")
        if not admin_role:
            admin_role = datastore.create_role(name="admin", description="Administrator")
        user_role = datastore.find_role("user")
        if not user_role:
            user_role = datastore.create_role(name="user", description="Default user")

        user = datastore.create_user(email=email_normalized, password=hash_password(password), roles=[admin_role, user_role])
        db.session.commit()
        click.echo(f"管理员 {user.email} 创建成功")
